#include <core/network/network_manager.h>
#include <core/rpc/rpc_manager.h>
#include <core/task/task_manager.h>

#include <ranges>

#include <gflags/gflags_declare.h>
#include <thirdparty/fist-log.h>

#include "svc_base.h"
#include "svc_info.h"
#include "svc_conf.h"


DECLARE_string(svc_name);
DECLARE_int32(svc_type);
DECLARE_int32(svc_id);

std::string __g_service_real_name__;
uint16_t __g_service_listen_port__;

CBoxBase::CBoxBase()
    : m_network(nullptr)
    , m_box_conf(new CBoxParser())
    , m_need_stop(false)
    , m_last_update(0)
{
    
}

CBoxBase::~CBoxBase()
{
    delete m_box_conf;
    for (auto iter = m_managers.begin(); iter != m_managers.end(); ++iter) {
        delete iter->second;
    }
}

bool CBoxBase::Init()
{
    if (!m_box_conf->Load("../config/box/box.xml")) {
        return false;
    }

    auto boxes = cfg()->services.find(FLAGS_svc_type);
    if (boxes == cfg()->services.end()) {
        LOG_FATAL("service type not found. type:{}", FLAGS_svc_type);
        return false;
    }
    auto box = boxes->second.find(FLAGS_svc_id);
    if (box == boxes->second.end()) {
        LOG_FATAL("service id not found. id:{}", FLAGS_svc_id);
        return false;
    }
    m_box_info = box->second;
    __g_service_real_name__ = box->second.name;
    __g_service_listen_port__ = static_cast<uint16_t>(box->second.listen);

    m_network = new CNetworkManager();
    AddComponent(m_network);
    if (!m_network->Init()) {
        return false;
    }
    IRpcManager* rpc = new CRpcManager();
    if (!AddComponent(rpc)) {
        return false;
    }
    m_network->RegisterRawPackHandle(RAWPACKTYPE_RPC, rpc);
    AddComponent(new CTaskManager);

    if (!CollectManager()) {
        return false;
    }
    for (auto& p : m_managers | std::views::values) {
        if (p->hash_code() != m_network->hash_code() && !p->Init()) {
            LOG_FATAL("manager init error. id:{}, name:{}", p->hash_code(), p->name());
            return false;
        }
    }
    return true;
}

bool CBoxBase::Run()
{
    while (!m_need_stop) {
        m_network->Run();
        if (fist::get_now_ms_time() > m_last_update) {
            Update();
            m_last_update = fist::get_now_ms_time() + m_box_info.tick;
        }
    }
    return true;
}

void CBoxBase::Update()
{
    for (auto& p : m_managers | std::views::values) {
        p->Update();
    }
}
void CBoxBase::Destroy()
{
    for (auto& p : m_managers | std::views::values) {
        p->Destroy();
    }
}

bool CBoxBase::AddComponent(IManager* p)
{
    LOG_INFO("add manager. id:{}, name:{}", p->hash_code(), p->name());
    if (auto ret = m_managers.insert({ p->hash_code(), p }); !ret.second) {
        LOG_FATAL("manager id had exist. id:{}, name:{}, exist:{}", p->hash_code(), p->name(), 
            ret.first->second->name());
        return false;
    }
    p->set_box(this);
    return true;
}

bool CBoxBase::AddConnect(const BoxInfo* info)
{
    netlink_t link = m_network->AddConnect(info->ip, info->listen);
    if (link == INVALID_LINK) {
        return false;
    }
    auto f = m_peers.find(info->type);
    if (f == m_peers.end()) {
        std::vector<std::pair<netlink_t, BoxInfo>> netlinks;
        netlinks.emplace_back(link, *info);
        m_peers.insert({ info->type, netlinks});
    } else {
        f->second.emplace_back(link, *info);
    }
    return true;
}

bool CBoxBase::AddConnect(int type)
{
    auto con = cfg()->services.find(type);
    if (con == cfg()->services.end()) {
        LOG_ERROR("not find any box. type:{}", type);
        return false;
    }
    for (auto& item : con->second | std::views::values) {
        if (!AddConnect(&item)) {
            LOG_ERROR("connect peer fail! please Check the order in which the services are started. "
                "type:{}, peer:{}, port:%u", type, item.ip, item.listen);
            return false;
        }
    }
    return true;
}

std::unordered_map<size_t, IManager*>* CBoxBase::managers()
{
    return &m_managers;
}

std::unordered_map<int, std::vector<std::pair<netlink_t, BoxInfo>>>* CBoxBase::peers()
{
    return &m_peers;
}

bool CBoxBase::Reconnect(int type, netlink_t link)
{
    auto f = m_peers.find(type);
    if (f == m_peers.end()) {
        LOG_ERROR("connect type not exist! type:{}", type);
        return false;
    }
    auto old = f->second.end();
    for (auto iter = f->second.begin(); iter != f->second.end(); ++iter) {
        if (iter->first == link) {
            old = iter;
            break;
        }
    }
    if (old == f->second.end()) {
        LOG_ERROR("connect not exist! old:%p", old->first);
        return false;
    }
    BoxInfo box = old->second;
    f->second.erase(old);
    return AddConnect(&box);
}

void CBoxBase::Stop()
{
    m_need_stop = true;
}

const BoxConf* CBoxBase::cfg()
{
    return m_box_conf->cfg();
}
